package com.sgchen.security.config;

import com.sgchen.security.annotation.ConditionalOnNoSubclass;
import com.sgchen.security.util.ReflectionsLogToggler;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.*;

/**
 * 自定义条件：当没有子类时生效
 */
public class NoSubclassCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        try {
            Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnNoSubclass.class.getName(), true);
            if (attributes == null) {
                return true;
            }
            // 获取当前类名
            String className = attributes.get("value").toString();
            Class<?> parentClass = Class.forName(className);
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            if(beanFactory==null){
                return true;
            }
            Set<String> possiblePackages = new HashSet<>();
            String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
            for (String definitionName : beanDefinitionNames) {
                String beanClassName = beanFactory.getBeanDefinition(definitionName).getBeanClassName();
                if(StringUtils.isNotEmpty(beanClassName)
                        && beanClassName.contains(".")
                        && !beanClassName.contains("org.springframework")){
                    String packageName = beanClassName.substring(0, beanClassName.lastIndexOf('.'));
                    possiblePackages.add(packageName);
                }
            }
            Set<String> commonPackages = extractPrefixes(possiblePackages);
            // 创建Reflections实例
            Reflections reflections = ReflectionsLogToggler.executeSilently(() -> {
                ConfigurationBuilder config = new ConfigurationBuilder()
                        .forPackages(commonPackages.toArray(new String[0]))
                        .setScanners(new SubTypesScanner());

                return new Reflections(config);
            });
            // 获取所有子类
            Set<Class<? extends Object>> subTypes = (Set<Class<?>>) reflections.getSubTypesOf(parentClass);
            // 排除父类本身
            subTypes.remove(parentClass);
            return subTypes.isEmpty();
        } catch (Exception ex) {
            // 发生异常时默认不满足条件
            return true;
        }
    }

    public static Set<String> extractPrefixes(Set<String> strings) {
        Set<String> result = new HashSet<>();
        for (String candidate : strings) {
            for (String other : strings) {
                if (!candidate.equals(other) && other.startsWith(candidate)) {
                    result.add(candidate);
                    break;
                }
            }
        }
        return result;
    }
}